/**
 * Name: LightsBorad
 * @author Zhongtian Jiang
 * @version 1.0
 * This is a Panel represents the whole board
 */
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;


/**
 * @author Master
 * @version $Revision: 1.0 $
 */
public class LightsBoard extends JPanel{
	/**
	 * Field SI.
	 * (value is 4)
	 */
	private static final int SI = 4;

	/**
	 * Field MMM.
	 */
	/**
	 * Field NNN.
	 */
	public int nNN, mMM;

	/**
	 * Field aaa.
	 */
	public Tile[][] aaa;

	/**
	 * Field PPP.
	 */
	public static final int[] PPP={1, -1, 0, 0};

	/**
	 * Field QQQ.
	 */
	public static final int[] QQQ={0, 0, 1, -1};

	/**
	 * Field on.
	 */
	private boolean on[][];

	/**
	 * Field ret.
	 */
	/**
	 * Field mm.
	 */
	/**
	 * Field nn.
	 */
	public int nn, mm, ret;

	/**
	 * Field Father.
	 */
	public LightsPanel fFather;

	/**
	 * Constructor for LightsBoard.
	 * @param n int
	 * @param m int
	 * @param father LightsPanel
	 */
	public LightsBoard(int n, int m, LightsPanel father){
		setLayout(new GridLayout(n, m));
		nNN=n;
		mMM=m;
		fFather=father;
		aaa=new Tile[nNN][mMM];
		
		for (int i=0;i < nNN;i++){
			for (int j=0;j < mMM;j++){
				aaa[i][j]=new Tile();
				add(aaa[i][j]);
				aaa[i][j].addMouseListener(new Clicklistener());
			}
		}
	}

	/**
     * simulate a click on grid cx,cy, but won't display
     * @param cx cy, the coordinate of the grid
    
     * @param cy int
	 */
	private void changeOn(int cx, int cy){
		on[cx][cy]=!on[cx][cy];
		for (int j=0;j < SI;j++){
			int tx=cx + PPP[j], ty=cy + QQQ[j];
			if (tx >= 0 && ty >= 0 && tx < nn && ty < mm) on[tx][ty]=!on[tx][ty]; 
		}
	}

	/**
     * return if it's necessary to click on grid cx,cy
     * @param cx cy, the coordinate of the grid
    
     * @param cy int
	 * @return if the grid need to change or not */
	private int needChange(int cx, int cy){
		if (!on[cx - 1][cy]) return 1;
		return 0;
	}

	/**
     * calcuate the minimun step to win
     * @return the minimum step to win */
	public int getMinimumStep(){
		ret=-1;
		nn=Math.max(nNN, mMM);
		mm=Math.min(nNN, mMM);
		boolean rotated=(nNN < mMM);
		for (int mask=0;mask < (1 << mm);mask++){
			on=new boolean[nn][mm];
			for (int i=0;i < nn;i++){
				for (int j=0;j < mm;j++){
					if (!rotated) {
						on[i][j]=aaa[i][j].isOn();
					}else on[i][j]=aaa[j][i].isOn();
				}
			}
			int cnt=0;
			for (int i=0;i < mm;i++){
				if (((1 << i) & mask) > 0){
					cnt++;
					changeOn(0, i);
				}
			}
			for (int i=1;i < nn;i++){
				for (int j=0;j < mm;j++){
					int tmp=needChange(i, j);
					if (tmp == 1) changeOn(i, j);
					cnt+=tmp;
					
				}
			}
			boolean flag=true;
			for (int i=0;i < nn;i++){
				for (int j=0;j < mm;j++){
					if (!on[i][j]) flag=false;
				}
			}
			if (flag){
				if (ret == -1 || cnt < ret) ret = cnt;
			}
		}
		return ret;
	}

	/**
     * find and display the grid as a hint to click next
     */
	public void toGetHint(){
		final int curStep = getMinimumStep();
		boolean flag = false;
		for (int i=0;i < nNN;i++){
			if (flag) break;
			for (int j=0;j < mMM;j++){
				Tile cur = aaa[i][j];
				cur.changeStatusWithoutDisplay();
				for (int k=0;k < SI;k++){
					Tile tmp=getNeighbor(cur, k);
					if (tmp != null) tmp.changeStatusWithoutDisplay();
				}
				if (getMinimumStep() == curStep - 1){
					cur.shine();
					flag=true;
				}
				cur.changeStatusWithoutDisplay();
				for (int k=0;k < SI;k++){
					Tile tmp=getNeighbor(cur, k);
					if (tmp != null) tmp.changeStatusWithoutDisplay();
				}
				if (flag) break;
			}
		}
	}

	/**
     * reset the whole board
     */
	public void reset() {
		for (int i=0;i < nNN;i++){
			for (int j=0;j < mMM;j++){
				if (aaa[i][j].isOn()){
					aaa[i][j].changeStatus();
				}else {
					aaa[i][j].changeStatus();
					aaa[i][j].changeStatus();
				}
			}
		}
		fFather.reCalculate();
	}

	/**
     * return an adjacent Tile of current Tile in certain direction
     * @param cur the current Tile, direction a certain direction
     * @param direction int
	 * @return the adjacent Tile, if it does not exist, return null; */
	public Tile getNeighbor(Tile cur, int direction){
		int cx=-1, cy=-1;
		for (int i=0;i < nNN;i++){
			for (int j=0;j < mMM;j++){
				if (cur.equals(aaa[i][j])) {
					cx=i;
					cy=j;
				}
			}
		}
		final int tx = cx + PPP[direction], ty=cy + QQQ[direction];
		if (tx >= nNN || tx < 0 || ty >= mMM || ty < 0) return null;
		return aaa[tx][ty];
	}

	/**
	 * @author 522sk
	 */
	public class Clicklistener implements MouseListener{
		/**
		 * Field YIQIAN.
		 * (value is 1000)
		 */
		private static final int YIQIAN = 1000;

		/**
		 * Method toString.
		
		 * @return String */
		@Override
		public String toString() {
			return "clicklistener []";
		}

		/**
		 * Method mouseClicked.
		 * @param e MouseEvent
		
		 * @see java.awt.event.MouseListener#mouseClicked(MouseEvent) */
		@Override
		public void mouseClicked(MouseEvent e) {
			final Tile cur = (Tile) e.getSource();
			cur.changeStatus();
			for (int i=0;i < SI;i++){
				Tile tmp=getNeighbor(cur, i);
				if (tmp != null) tmp.changeStatus();
			}
			fFather.reCalculate();
			boolean flag=true;
			for (int i=0;i < nNN;i++){
				for (int j=0;j < mMM;j++){
					if (!aaa[i][j].isOn()) flag=false;
				}
			}
			if (flag) {
				LightsMain.Frame.dispose();
				final int val=GameInfo.Rand.nextInt(YIQIAN);
				PlayerInfo.Money+=val;
				JOptionPane.showMessageDialog(
					getParent(),
					"You found the treasure in the temple which worthes " + val);
				MarketPlaceScreen.Money.setText("" + PlayerInfo.getMoney());
			}
			return;
			
		}

		/**
		 * Method mousePressed.
		 * @param e MouseEvent
		
		 * @see java.awt.event.MouseListener#mousePressed(MouseEvent) */
		@Override
		public void mousePressed(MouseEvent e) {
			new ExitInfoListener();
		}

		/**
		 * Method mouseReleased.
		 * @param e MouseEvent
		
		 * @see java.awt.event.MouseListener#mouseReleased(MouseEvent) */
		@Override
		public void mouseReleased(MouseEvent e) {
			new ExitInfoListener();
		}

		/**
		 * Method mouseEntered.
		 * @param e MouseEvent
		
		 * @see java.awt.event.MouseListener#mouseEntered(MouseEvent) */
		@Override
		public void mouseEntered(MouseEvent e) {
			new ExitInfoListener();
		}

		/**
		 * Method mouseExited.
		 * @param e MouseEvent
		
		 * @see java.awt.event.MouseListener#mouseExited(MouseEvent) */
		@Override
		public void mouseExited(MouseEvent e) {
			new ExitInfoListener();
		}
		
	}
	
}
